/*     */ package com.zimbra.cs.store.file;
/*     */ 
/*     */ import com.google.common.collect.Multimap;
/*     */ import com.zimbra.common.service.ServiceException;
/*     */ import com.zimbra.common.soap.AdminConstants;
/*     */ import com.zimbra.common.soap.Element;
/*     */ import com.zimbra.common.soap.Element.XMLElement;
/*     */ import com.zimbra.common.util.CliUtil;
/*     */ import com.zimbra.cs.account.soap.SoapProvisioning;
/*     */ import com.zimbra.cs.db.DbPool;
/*     */ import com.zimbra.soap.admin.message.ExportAndDeleteItemsRequest;
/*     */ import com.zimbra.soap.admin.type.ExportAndDeleteItemSpec;
/*     */ import com.zimbra.soap.admin.type.ExportAndDeleteMailboxSpec;
/*     */ import java.io.File;
/*     */ import java.io.FileOutputStream;
/*     */ import java.io.PrintStream;
/*     */ import java.io.PrintWriter;
/*     */ import java.util.ArrayList;
/*     */ import java.util.Iterator;
/*     */ import java.util.List;
/*     */ import org.apache.commons.cli.CommandLine;
/*     */ import org.apache.commons.cli.GnuParser;
/*     */ import org.apache.commons.cli.HelpFormatter;
/*     */ import org.apache.commons.cli.Option;
/*     */ import org.apache.commons.cli.Options;
/*     */ import org.apache.commons.cli.ParseException;
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ public class BlobConsistencyUtil
/*     */ {
/*     */   private static final String LO_HELP = "help";
/*     */   private static final String LO_VERBOSE = "verbose";
/*     */   private static final String LO_MAILBOXES = "mailboxes";
/*     */   private static final String LO_VOLUMES = "volumes";
/*     */   private static final String LO_SKIP_SIZE_CHECK = "skip-size-check";
/*     */   private static final String LO_UNEXPECTED_BLOB_LIST = "unexpected-blob-list";
/*     */   private static final String LO_MISSING_BLOB_DELETE_ITEM = "missing-blob-delete-item";
/*     */   private static final String LO_INCORRECT_REVISION_RENAME_FILE = "incorrect-revision-rename-file";
/*     */   private static final String LO_EXPORT_DIR = "export-dir";
/*     */   private static final String LO_NO_EXPORT = "no-export";
/*     */   private static final String LO_OUTPUT_USED_BLOBS = "output-used-blobs";
/*     */   private static final String LO_USED_BLOB_LIST = "used-blob-list";
/*     */   private Options options;
/*     */   private List<Integer> mailboxIds;
/*  62 */   private List<Short> volumeIds = new ArrayList();
/*  63 */   private boolean skipSizeCheck = false;
/*  64 */   private boolean verbose = false;
/*     */   private String unexpectedBlobList;
/*     */   private PrintWriter unexpectedBlobWriter;
/*  67 */   private boolean missingBlobDeleteItem = false;
/*  68 */   private boolean noExport = false;
/*     */   private String exportDir;
/*  70 */   private boolean incorrectRevisionRenameFile = false;
/*  71 */   private boolean outputUsedBlobs = false;
/*     */   private String usedBlobList;
/*     */   private PrintWriter usedBlobWriter;
/*     */   
/*     */   private BlobConsistencyUtil() {
/*  76 */     this.options = new Options();
/*     */     
/*  78 */     this.options.addOption(new Option("h", "help", false, "Display this help message."));
/*  79 */     this.options.addOption(new Option("v", "verbose", false, "Display verbose output.  Display stack trace on error."));
/*  80 */     this.options.addOption(new Option(null, "skip-size-check", false, "Skip blob size check."));
/*  81 */     this.options.addOption(new Option(null, "output-used-blobs", false, "Output listing of all blobs referenced by the mailbox(es)"));
/*     */     
/*  83 */     Option o = new Option(null, "volumes", true, "Specify which volumes to check.  If not specified, check all volumes.");
/*  84 */     o.setArgName("volume-ids");
/*  85 */     this.options.addOption(o);
/*     */     
/*  87 */     o = new Option("m", "mailboxes", true, "Specify which mailboxes to check.  If not specified, check all mailboxes.");
/*  88 */     o.setArgName("mailbox-ids");
/*  89 */     this.options.addOption(o);
/*     */     
/*  91 */     o = new Option(null, "unexpected-blob-list", true, "Write the paths of any unexpected blobs to a file.");
/*  92 */     o.setArgName("path");
/*  93 */     this.options.addOption(o);
/*     */     
/*  95 */     o = new Option(null, "used-blob-list", true, "Write the paths of all used blobs to a file.");
/*  96 */     o.setArgName("path");
/*  97 */     this.options.addOption(o);
/*     */     
/*  99 */     this.options.addOption(null, "missing-blob-delete-item", false, "Delete any items that have a missing blob.");
/*     */     
/* 101 */     o = new Option(null, "export-dir", true, "Target directory for database export files.");
/* 102 */     o.setArgName("path");
/* 103 */     this.options.addOption(o);
/*     */     
/* 105 */     this.options.addOption(null, "no-export", false, "Delete items without exporting.");
/* 106 */     this.options.addOption(new Option(null, "incorrect-revision-rename-file", false, "Rename the file on disk when the revision number doesn't match."));
/*     */   }
/*     */   
/*     */   private void usage(String errorMsg)
/*     */   {
/* 111 */     int exitStatus = 0;
/*     */     
/* 113 */     if (errorMsg != null) {
/* 114 */       System.err.println(errorMsg);
/* 115 */       exitStatus = 1;
/*     */     }
/* 117 */     HelpFormatter format = new HelpFormatter();
/* 118 */     format.printHelp(new PrintWriter(System.err, true), 80, "zmblobchk [options] start", null, this.options, 2, 2, "\nThe \"start\" command is required, to avoid unintentionally running a blob check.  Id values are separated by commas.");
/*     */     
/*     */ 
/*     */ 
/* 122 */     System.exit(exitStatus);
/*     */   }
/*     */   
/*     */   private void parseArgs(String[] args) throws ParseException
/*     */   {
/* 127 */     GnuParser parser = new GnuParser();
/* 128 */     CommandLine cl = parser.parse(this.options, args);
/*     */     
/* 130 */     if (CliUtil.hasOption(cl, "help")) {
/* 131 */       usage(null);
/*     */     }
/*     */     
/*     */ 
/* 135 */     if ((cl.getArgs().length == 0) || (!cl.getArgs()[0].equals("start"))) {
/* 136 */       usage(null);
/*     */     }
/*     */     
/* 139 */     String volumeList = CliUtil.getOptionValue(cl, "volumes");
/* 140 */     if (volumeList != null) {
/* 141 */       for (String id : volumeList.split(",")) {
/*     */         try {
/* 143 */           this.volumeIds.add(Short.valueOf(Short.parseShort(id)));
/*     */         } catch (NumberFormatException e) {
/* 145 */           usage("Invalid volume id: " + id);
/*     */         }
/*     */       }
/*     */     }
/*     */     
/* 150 */     String mailboxList = CliUtil.getOptionValue(cl, "mailboxes");
/* 151 */     if (mailboxList != null) {
/* 152 */       this.mailboxIds = new ArrayList();
/* 153 */       for (String id : mailboxList.split(",")) {
/*     */         try {
/* 155 */           this.mailboxIds.add(Integer.valueOf(Integer.parseInt(id)));
/*     */         } catch (NumberFormatException e) {
/* 157 */           usage("Invalid mailbox id: " + id);
/*     */         }
/*     */       }
/*     */     }
/*     */     
/* 162 */     this.skipSizeCheck = CliUtil.hasOption(cl, "skip-size-check");
/* 163 */     this.verbose = CliUtil.hasOption(cl, "verbose");
/* 164 */     this.unexpectedBlobList = CliUtil.getOptionValue(cl, "unexpected-blob-list");
/* 165 */     this.missingBlobDeleteItem = CliUtil.hasOption(cl, "missing-blob-delete-item");
/* 166 */     this.exportDir = CliUtil.getOptionValue(cl, "export-dir");
/* 167 */     this.outputUsedBlobs = CliUtil.hasOption(cl, "output-used-blobs");
/* 168 */     this.usedBlobList = CliUtil.getOptionValue(cl, "used-blob-list");
/*     */     
/* 170 */     if (this.missingBlobDeleteItem)
/*     */     {
/* 172 */       if (this.exportDir == null) {
/* 173 */         this.noExport = CliUtil.hasOption(cl, "no-export");
/* 174 */         if (!this.noExport) {
/* 175 */           usage("Please specify either export-dir or no-export when using missing-blob-delete-item");
/*     */         }
/*     */       }
/*     */     }
/*     */     
/* 180 */     this.incorrectRevisionRenameFile = CliUtil.hasOption(cl, "incorrect-revision-rename-file");
/*     */   }
/*     */   
/*     */   private void run() throws Exception
/*     */   {
/* 185 */     if (this.unexpectedBlobList != null) {
/* 186 */       this.unexpectedBlobWriter = new PrintWriter(new FileOutputStream(this.unexpectedBlobList), true);
/*     */     }
/*     */     
/* 189 */     if (this.usedBlobList != null) {
/* 190 */       this.usedBlobWriter = new PrintWriter(new FileOutputStream(this.usedBlobList), true);
/*     */     }
/*     */     
/* 193 */     CliUtil.toolSetup();
/* 194 */     SoapProvisioning prov = SoapProvisioning.getAdminInstance();
/* 195 */     prov.soapZimbraAdminAuthenticate();
/* 196 */     if (this.mailboxIds == null) {
/* 197 */       this.mailboxIds = getAllMailboxIds(prov);
/*     */     }
/*     */     try {
/* 200 */       DbPool.startup();
/* 201 */       for (i$ = this.mailboxIds.iterator(); i$.hasNext();) { int mboxId = ((Integer)i$.next()).intValue();
/* 202 */         System.out.println("Checking mailbox " + mboxId + ".");
/* 203 */         checkMailbox(mboxId, prov);
/*     */       }
/*     */     } finally { Iterator i$;
/* 206 */       DbPool.shutdown();
/*     */     }
/* 208 */     if (this.unexpectedBlobWriter != null) {
/* 209 */       this.unexpectedBlobWriter.close();
/*     */     }
/*     */     
/* 212 */     if (this.usedBlobWriter != null) {
/* 213 */       this.usedBlobWriter.close();
/*     */     }
/*     */   }
/*     */   
/*     */   private List<Integer> getAllMailboxIds(SoapProvisioning prov) throws ServiceException
/*     */   {
/* 219 */     List<Integer> ids = new ArrayList();
/* 220 */     Element.XMLElement request = new Element.XMLElement(AdminConstants.GET_ALL_MAILBOXES_REQUEST);
/* 221 */     Element response = prov.invoke(request);
/* 222 */     for (Element mboxEl : response.listElements("mbox")) {
/* 223 */       ids.add(Integer.valueOf((int)mboxEl.getAttributeLong("id")));
/*     */     }
/* 225 */     return ids;
/*     */   }
/*     */   
/*     */   private String locatorText(BlobConsistencyChecker.BlobInfo blob) {
/* 229 */     if (blob.external) {
/* 230 */       return String.format("locator %s", new Object[] { blob.path });
/*     */     }
/* 232 */     return String.format("volume %d, %s", new Object[] { Short.valueOf(blob.volumeId), blob.path });
/*     */   }
/*     */   
/*     */   private void checkMailbox(int mboxId, SoapProvisioning prov)
/*     */     throws ServiceException
/*     */   {
/* 238 */     Element.XMLElement request = new Element.XMLElement(AdminConstants.CHECK_BLOB_CONSISTENCY_REQUEST);
/* 239 */     for (Iterator i$ = this.volumeIds.iterator(); i$.hasNext();) { short volumeId = ((Short)i$.next()).shortValue();
/* 240 */       request.addElement("volume").addAttribute("id", volumeId);
/*     */     }
/* 242 */     request.addElement("mbox").addAttribute("id", mboxId);
/* 243 */     request.addAttribute("checkSize", !this.skipSizeCheck);
/* 244 */     request.addAttribute("reportUsedBlobs", (this.outputUsedBlobs) || (this.usedBlobWriter != null));
/*     */     
/* 246 */     Element response = prov.invoke(request);
/* 247 */     for (Element mboxEl : response.listElements("mbox"))
/*     */     {
/* 249 */       BlobConsistencyChecker.Results results = new BlobConsistencyChecker.Results(mboxEl);
/* 250 */       for (BlobConsistencyChecker.BlobInfo blob : results.missingBlobs.values()) {
/* 251 */         System.out.format("Mailbox %d, item %d, rev %d, %s: blob not found.\n", new Object[] { Integer.valueOf(results.mboxId), Integer.valueOf(blob.itemId), Integer.valueOf(blob.modContent), locatorText(blob) });
/*     */       }
/*     */       
/* 254 */       for (BlobConsistencyChecker.BlobInfo blob : results.incorrectSize.values()) {
/* 255 */         System.out.format("Mailbox %d, item %d, rev %d, %s: incorrect data size.  Expected %d, was %d.  File size is %d.\n", new Object[] { Integer.valueOf(results.mboxId), Integer.valueOf(blob.itemId), Integer.valueOf(blob.modContent), locatorText(blob), Long.valueOf(blob.dbSize), blob.fileDataSize, blob.fileSize });
/*     */       }
/*     */       
/*     */ 
/*     */ 
/*     */ 
/* 261 */       for (BlobConsistencyChecker.BlobInfo blob : results.unexpectedBlobs.values()) {
/* 262 */         System.out.format("Mailbox %d, %s: unexpected blob.  File size is %d.\n", new Object[] { Integer.valueOf(results.mboxId), locatorText(blob), blob.fileSize });
/*     */         
/*     */ 
/* 265 */         if (this.unexpectedBlobWriter != null) {
/* 266 */           this.unexpectedBlobWriter.println(blob.path);
/*     */         }
/*     */       }
/* 269 */       for (BlobConsistencyChecker.BlobInfo blob : results.incorrectModContent.values()) {
/* 270 */         System.out.format("Mailbox %d, item %d, rev %d, %s: file has incorrect revision.\n", new Object[] { Integer.valueOf(results.mboxId), Integer.valueOf(blob.itemId), Integer.valueOf(blob.modContent), locatorText(blob) });
/*     */       }
/*     */       
/*     */ 
/* 274 */       for (BlobConsistencyChecker.BlobInfo blob : results.usedBlobs.values()) {
/* 275 */         if (this.outputUsedBlobs) {
/* 276 */           System.out.format("Used blob: Mailbox %d, item %d, rev %d, %s.\n", new Object[] { Integer.valueOf(results.mboxId), Integer.valueOf(blob.itemId), Integer.valueOf(blob.version), locatorText(blob) });
/*     */         }
/*     */         
/*     */ 
/* 280 */         if (this.usedBlobWriter != null) {
/* 281 */           this.usedBlobWriter.println(blob.path);
/*     */         }
/*     */       }
/*     */       
/*     */ 
/* 286 */       if ((this.missingBlobDeleteItem) && (results.missingBlobs.size() > 0)) {
/* 287 */         exportAndDelete(prov, results);
/*     */       }
/* 289 */       if (this.incorrectRevisionRenameFile) {
/* 290 */         for (BlobConsistencyChecker.BlobInfo blob : results.incorrectModContent.values()) {
/* 291 */           File file = new File(blob.path);
/* 292 */           File dir = file.getParentFile();
/* 293 */           if (dir != null) {
/* 294 */             File newFile = new File(dir, FileBlobStore.getFilename(blob.itemId, blob.modContent));
/* 295 */             System.out.format("Renaming %s to %s.\n", new Object[] { file.getAbsolutePath(), newFile.getAbsolutePath() });
/* 296 */             if (!file.renameTo(newFile)) {
/* 297 */               System.err.format("Unable to rename %s to %s.\n", new Object[] { file.getAbsolutePath(), newFile.getAbsolutePath() });
/*     */             }
/*     */           } else {
/* 300 */             System.err.format("Could not determine parent directory of %s.\n", new Object[] { file.getAbsolutePath() });
/*     */           }
/*     */         }
/*     */       }
/*     */     }
/*     */   }
/*     */   
/*     */   private void exportAndDelete(SoapProvisioning prov, BlobConsistencyChecker.Results results) throws ServiceException
/*     */   {
/* 309 */     System.out.format("Deleting %d items from mailbox %d.\n", new Object[] { Integer.valueOf(results.missingBlobs.size()), Integer.valueOf(results.mboxId) });
/*     */     
/* 311 */     ExportAndDeleteMailboxSpec mailbox = new ExportAndDeleteMailboxSpec(results.mboxId);
/* 312 */     ExportAndDeleteItemsRequest jaxbRequest = new ExportAndDeleteItemsRequest(this.exportDir, "mbox" + results.mboxId + "_", mailbox);
/*     */     
/* 314 */     for (BlobConsistencyChecker.BlobInfo blob : results.missingBlobs.values()) {
/* 315 */       mailbox.addItem(ExportAndDeleteItemSpec.createForIdAndVersion(blob.itemId, blob.version));
/*     */     }
/* 317 */     prov.invokeJaxb(jaxbRequest);
/*     */   }
/*     */   
/*     */   public static void main(String[] args) {
/* 321 */     BlobConsistencyUtil app = new BlobConsistencyUtil();
/*     */     try
/*     */     {
/* 324 */       app.parseArgs(args);
/*     */     } catch (ParseException e) {
/* 326 */       app.usage(e.getMessage());
/*     */     }
/*     */     try
/*     */     {
/* 330 */       app.run();
/*     */     } catch (Exception e) {
/* 332 */       if (app.verbose) {
/* 333 */         e.printStackTrace(new PrintWriter(System.err, true));
/*     */       } else {
/* 335 */         String msg = e.getMessage();
/* 336 */         if (msg == null) {
/* 337 */           msg = e.toString();
/*     */         }
/* 339 */         System.err.println(msg);
/*     */       }
/* 341 */       System.exit(1);
/*     */     }
/*     */   }
/*     */ }


/* Location:              /home/mint/zimbrastore.jar!/com/zimbra/cs/store/file/BlobConsistencyUtil.class
 * Java compiler version: 7 (51.0)
 * JD-Core Version:       0.7.1
 */